package org.molamil.acto.expressions{
	import flash.utils.getQualifiedClassName;
	import org.molamil.acto.core.parsers.ResolverError;
	import org.molamil.acto.core.loggers.Logger;
	import org.molamil.acto.core.parsers.PrioritizableList;
	import org.molamil.acto.utils.ObjectUtils;		import org.molamil.acto.utils.StringUtils;	
	
	/**	 * XXX: Document.	 * 	 * @author Jorge Hernandez	 */	public class ExpressionResolver extends PrioritizableList {						// CONSTANTS		private static const logger:Logger = Logger.getLogger("ExpressionResolver");
				public static const pattern:RegExp = /([^\\]|^)\{.*[^\\]\}/;				public static const ERROR_MISSING_CLOSING:String = "ERROR: Missing closing tag in expression: '{expression}'";		// PROPERTIES				public static var opening:String = "{";		public static var closing:String = "}";				private static var resolvers:Array = [DefaultExpressionEvaluator];
				private static var _instance : ExpressionResolver;
				
		
		// CONSTRUCTOR
		
		public function ExpressionResolver() {
			for (var i:Number = 0; i < resolvers.length; i++)
				add(new resolvers[i]());
		}
		
				// PUBLIC STATIC METHODS
		public static function getInstance():ExpressionResolver {
			if(_instance==null){
				_instance=new ExpressionResolver();			}
			return _instance;
		}				//XXX: Align with getExpressions		public static function test(s:String):Boolean {			return pattern.test(s);
		}
		
				public static function getExpressions(input:String):Array {						if (input == null)				return null;							var a:Array = input.split(opening);			var expressions:Array = new Array();			for (var i:int = 1; i < a.length; i++) {				var prevToken:String = a[i - 1];				if (prevToken.charAt(prevToken.length - 1) == "\\")					continue;				var token:String = a[i];				var endIndex:Number = token.indexOf(closing);				if (endIndex == -1)					throw new InvalidExpressionError(ERROR_MISSING_CLOSING.replace("{expression}", token));				token = StringUtils.trim(token.substring(0, endIndex));				expressions.push(token);			}			return expressions;					}				public static function resolve(input:String, data:Object):* {			return getInstance().doResolve(input, data);		}
						
		
		
		
		// PUBLIC METHODS

		public function registerEvaluator(resolver:AbstractExpressionEvaluator):void{
			add(resolver);
		}
		
		public function doResolve(input:String, data:Object):* {

			if (input == null)
				return null;
				
			var a:Array = input.split(opening);
			var outputText:String = a[0];
			var output:*;
			var value:*;
			for (var i:int = 1; i < a.length; i++) {
				var prevToken:String = a[i - 1];
				var token:String = a[i];
				if (prevToken.charAt(prevToken.length - 1) == "\\") {
					outputText += opening + token;
					continue;
				}
				var endIndex:Number = token.indexOf(closing);
				if (endIndex == -1)
					throw new InvalidExpressionError(ERROR_MISSING_CLOSING.replace("{expression}", token));
				var expression:String = StringUtils.trim(token.substring(0, endIndex));
				
				
				
				
				
				sort();
				
				for (var j:Number = 0; j < _a.length; j++) {
					var resolver:Evaluator = _a[j];
					try {
						value = resolver.evaluate(expression, data);
						logger.debug("value resolved to " + value);
						logger.debug("value resolved by " + getQualifiedClassName(resolver));
						break;
					} catch (e:ResolverError) {
						continue;
					}
				}



				
				var endText:String = token.substring(endIndex + 1);
				if (outputText != "" || endText != "")
					outputText += value + endText;
			}
			if (outputText != "") {
				outputText = outputText.replace("\\" + opening, opening).replace("\\" + closing, closing);
				output = outputText;
			} else {
				output = value;
			}
			return output;		}					}	}